package com.example.sunsg.okhttptest.http;

import android.text.TextUtils;
import android.util.Log;

import com.example.sunsg.okhttptest.TheApplication;
import com.example.sunsg.okhttptest.bean.KeyValue;
import com.example.sunsg.okhttptest.cookies.PersistentCookieStore;
import com.example.sunsg.okhttptest.util.GsonUtil;
import com.squareup.okhttp.Callback;
import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.Headers;
import com.squareup.okhttp.MediaType;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.RequestBody;
import com.squareup.okhttp.Response;



import java.io.File;
import java.io.IOException;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Created by sunsg on 15/9/21.
 */
public class OkHttpManager<T>{
    public static final String GET = "GET";
    public static final String POST = "POST";
    public static final String PUT = "PUT";
    public static final String DELETE = "DELETE";
    public static final String HEAD = "HEAD";
    public static final String PATCH = "PATCH";

    private static final OkHttpClient mOkHttpClient = new OkHttpClient();
    static{
        mOkHttpClient.setConnectTimeout(10, TimeUnit.SECONDS);
        mOkHttpClient.setCookieHandler(new CookieManager(new PersistentCookieStore(TheApplication.getApplication()), CookiePolicy.ACCEPT_ALL));
//        mOkHttpClient.networkInterceptors().add(new OkHttpInterceptor());
    }

    /**
     * 开启异步线程访问网络 get请求
     * @param url
     * @param responseCallback
     */
    public static void enqueue(String url, Callback responseCallback){
        Request request = new Request.Builder().url(url).build();
        mOkHttpClient.newCall(request).enqueue(responseCallback);
    }

    /**
     * 开启异步线程访问网络 get请求
     * @param url
     * @param responseCallback
     */
    public static void enqueue(String url, Headers headers,Callback responseCallback){
        Request request = new Request.Builder().url(url).headers(headers).tag(url).build();
        mOkHttpClient.newCall(request).enqueue(responseCallback);
    }


    /**
     * 开启异步线程访问网络 post 请求  优化headers
     * @param url
     * @param params
     * @param callback
     */
    public static void enqueuePost(String url, List<KeyValue> params, Callback callback){
        FormEncodingBuilder body = new FormEncodingBuilder();
        for (KeyValue np : params){
            body.add(np.getKey(),np.getValue());
        }
        String agent = "BreadTrip/android/6.1.0/zh (android OS5.0.1) trltechn Map/AutoNavi/v1.4.2 (SM-N9100,samsung)";
        Headers headers = new Headers.Builder().add("User-Agent", agent).build();
        Request request = new Request.Builder().url(url).post(body.build()).headers(headers).build();
        mOkHttpClient.newCall(request).enqueue(callback);



//        MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);
//        for (NameValuePair np : params){
//            builder.addFormDataPart(np.getName(), np.getValue());
//        }
////        builder.addPart(headers,null);
//        Request request2 = new Request.Builder().url(url).post(builder.build()).headers(headers).build();
//        mOkHttpClient.newCall(request2).enqueue(callback);
    }


    /**
     * 开启异步线程访问网络 post 请求  优化headers
     * @param url
     * @param params
     * @param callback
     * @param fileParms
     */
    public static void enqueuePost(String url,List<KeyValue> params,KeyValue fileParms,Callback callback){

        String agent = "BreadTrip/android/6.1.0/zh (android OS5.0.1) trltechn Map/AutoNavi/v1.4.2 (SM-N9100,samsung)";
        Headers headers = new Headers.Builder().add("User-Agent", agent).build();

        MultipartBuilder builder = new MultipartBuilder().type(MultipartBuilder.FORM);
        for (KeyValue np : params){
            builder.addFormDataPart(np.getKey(), np.getValue());
        }

        if(fileParms != null){
            File file = new File(fileParms.getValue());
            Log.i("test","name = "+fileParms.getKey() +" value = "+file.getAbsolutePath());
            if(file.exists()){
                Log.i("test","file exist");
                RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
                builder.addFormDataPart(fileParms.getKey(),file.getName(),fileBody);
            }else{
                Log.i("test","file not  exist");
            }
        }
        Request request = new Request.Builder().url(url).post(builder.build()).headers(headers).tag(fileParms.getValue()).build();
        Log.i("test","tag = "+request.tag().toString());
        mOkHttpClient.newCall(request).enqueue(callback);
    }


    /**
     * 该不会开启异步线程。
     * @param request
     * @return
     * @throws java.io.IOException
     */
    public static Response execute(Request request) throws IOException{
        return mOkHttpClient.newCall(request).execute();
    }


    /**
     * 开启异步线程访问网络, 且不在意返回结果（实现空callback）get请求
     * @param url
     */
    public static void enqueue(String url){
        Request request = new Request.Builder().url(url).build();
        mOkHttpClient.newCall(request).enqueue(new Callback() {

            @Override
            public void onResponse(Response arg0) throws IOException {

            }

            @Override
            public void onFailure(Request arg0, IOException arg1) {

            }
        });
    }

    public static String getStringFromServer(String url) throws IOException{
        Request request = new Request.Builder().url(url).build();
        Response response = execute(request);
        if (response.isSuccessful()) {
            String responseUrl = response.body().string();
            return responseUrl;
        } else {
            throw new IOException("Unexpected code " + response);
        }
    }
    private static final String CHARSET_NAME = "UTF-8";
//    /**
//     * 这里使用了HttpClinet的API。只是为了方便
//     * @param params
//     * @return
//     */
//    public static String formatParams(List<NameValuePair> params){
//        return URLEncodedUtils.format(params, CHARSET_NAME);
//    }
//    /**
//     * 为HttpGet 的 url 方便的添加多个name value 参数。
//     * @param url
//     * @param params
//     * @return
//     */
//    public static String attachHttpGetParams(String url, List<NameValuePair> params){
//        return url + "?" + formatParams(params);
//    }
//    /**
//     * 为HttpGet 的 url 方便的添加1个name value 参数。
//     * @param url
//     * @param name
//     * @param value
//     * @return
//     */
//    public static String attachHttpGetParam(String url, String name, String value){
//        return url + "?" + name + "=" + value;
//    }

    /**
     * 取消一个http请求
     */
    public static void cancelReqest(Object tag){
        mOkHttpClient.cancel(tag);
    }


    private String url;
    private String method;
    private Object tag;
    private Headers.Builder headers;
    private List<KeyValue> params;
    private KeyValue fileParmas;
    private Class classEntry;

    public OkHttpManager(Builder builder){
        this.url = builder.url;
        this.method = builder.method;
        this.tag = builder.tag;
        this.headers = builder.headers;
        this.params = builder.params;
        this.fileParmas = builder.fileParmas;
        this.classEntry = builder.classs;
    }

    /**
     * 异步执行网络请求
     */
    public void enqueue(Callback callback){
        //添加agent  在这里手动添加上
        String agent = "BreadTrip/android/6.1.0/zh (android OS5.0.1) trltechn Map/AutoNavi/v1.4.2 (SM-N9100,samsung)";
        headers.add("User-Agent", agent).build();

        MultipartBuilder builder = null;
        //添加参数
        if(params != null){
            builder = new MultipartBuilder().type(MultipartBuilder.FORM);
            for (KeyValue np : params){
                builder.addFormDataPart(np.getKey(), np.getValue());
            }
        }
        //添加文件参数
        if(fileParmas != null){
            if(builder == null){
                builder = new MultipartBuilder().type(MultipartBuilder.FORM);
            }
            File file = new File(fileParmas.getValue());
            if(file.exists()){
                RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
                builder.addFormDataPart(fileParmas.getKey(),file.getName(),fileBody);
            }
        }
        if(!TextUtils.isEmpty(url)){
            Log.i("test","url = "+url);
            //如果 builder ＝＝ null body传null
            Request request = new Request.Builder().url(url).method(method,builder != null ? builder.build() : null).headers(headers.build()).tag(url).build();
            mOkHttpClient.newCall(request).enqueue(callback);
        }else{
            throw new RuntimeException("url not exist ！");
        }

    }

    /**
     * 异步执行网络请求
     */
    public void enqueue2(final CallBack<T> callbacks){
        //添加agent  在这里手动添加上
        final String agent = "BreadTrip/android/6.1.0/zh (android OS5.0.1) trltechn Map/AutoNavi/v1.4.2 (SM-N9100,samsung)";
        headers.add("User-Agent", agent).build();

        MultipartBuilder builder = null;
        //添加参数
        if(params != null){
            builder = new MultipartBuilder().type(MultipartBuilder.FORM);
            for (KeyValue np : params){
                builder.addFormDataPart(np.getKey(), np.getValue());
            }
        }
        //添加文件参数
        if(fileParmas != null){
            if(builder == null){
                builder = new MultipartBuilder().type(MultipartBuilder.FORM);
            }
            File file = new File(fileParmas.getValue());
            if(file.exists()){
                RequestBody fileBody = RequestBody.create(MediaType.parse("application/octet-stream"), file);
                builder.addFormDataPart(fileParmas.getKey(),file.getName(),fileBody);
            }
        }
        if(!TextUtils.isEmpty(url)){
            Log.i("test","url = "+url);
            //如果 builder ＝＝ null body传null
            Request request = new Request.Builder().url(url).method(method,builder != null ? builder.build() : null).headers(headers.build()).tag(url).build();
            mOkHttpClient.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Request request, IOException e) {
                    callbacks.onFaile(request,e);
                }

                @Override
                public void onResponse(Response response) throws IOException {

                    T t = null;
                    if(classEntry != null){
                        long before = System.currentTimeMillis();
                        Log.i("test",before+"");
                        t = (T) GsonUtil.fromJson(response.body().string(),classEntry);
//                        String json = response.body().string();
//                        Log.i("test","json = "+json);
//                        t = (T) JSON.parseObject(json,classEntry);
                        long after = System.currentTimeMillis();
                        Log.i("test",after+"");
                        Log.i("test","char = "+(after - before));
                    }
                    callbacks.onSuccess(response,t);
                }
            });
        }else{
            throw new RuntimeException("url not exist ！");
        }

    }

    public static Builder get(String url){
        return new Builder(GET,url);
    }

    public static Builder post(String url){
        return new Builder(POST,url);
    }

    public static Builder put(String url){
        return new Builder(PUT,url);
    }

    public static Builder delete(String url){
        return new Builder(DELETE,url);
    }

    public static Builder head(String url){
        return new Builder(HEAD,url);
    }

    public static Builder patch(String url){
        return new Builder(PATCH,url);
    }

    public static class Builder {
        private String url;
        private String method;
        private Object tag;
        private Headers.Builder headers;
        private List<KeyValue> params;
        private KeyValue fileParmas;
        private Class classs;

        public Builder(){

        }

        public Builder(String method,String url){
            this.method = method;
            this.url = url;
            this.headers = new Headers.Builder();
        }


        /**
         * 网络请求头信息
         *
         * Removes all headers on this builder and adds {@code headers}.
         * @param headers
         * @return
         */
        public Builder headers(Headers headers){
            this.headers = headers.newBuilder();
            return this;
        }

        /**
         * 添加网络请求头信息
         *
         * Adds a header with {@code name} and {@code value}. Prefer this method for
         * multiply-valued headers like "Cookie"
         * @param name
         * @param value
         * @return
         */
        public Builder addHeader(String name,String value){
            headers.add(name,value);
            return this;
        }

        /**
         * 设置网络请求头信息
         *
         * Sets the header named {@code name} to {@code value}. If this request
         * already has any headers with that name, they are all replaced.
         *
         * @param name
         * @param value
         * @return
         */
        public Builder header(String name,String value){
            headers.set(name, value);
            return this;
        }

        /**
         * 网络请求参数
         * @param params
         * @return
         */
        public Builder params(List<KeyValue> params){
            this.params = params;
            return this;
        }

        /**
         * 文件请求参数
         * @param fileparam
         * @return
         */
        public Builder fileParam(KeyValue fileparam){
            this.fileParmas = fileparam;
            return this;
        }

        /**
         * CLASS
         * @param classs
         * @return
         */
        public Builder classs(Class classs){
            this.classs = classs;
            return this;
        }


        /**
         * 网络请求参数
         * @param tag
         * @return
         */
        public Builder tag(Object tag){
            this.tag = tag;
            return this;
        }

        public OkHttpManager builder(){
            return new OkHttpManager(this);
        }

    }

    public  interface CallBack<T>{
         void onSuccess(Response response,T t) throws IOException;
         void onFaile(Request request, IOException e);
    }

}
